#include "server.h"

#define WSCLIENT_DEF_NUM        4
#define WSCLIENT_MAX_NUM        100

struct cnfg_info cnfg_info;
struct stat_info stat_info;
struct operate_info operate_info;

extern int worker_start(SOCKET **p_sock_pair);
extern int listener_start(SOCKET *sock_pair);
extern int monitor_start();

static void _trim_line(char *line, int line_size)
{/*{{{*/
    int len;
    unsigned int quote;
    int i;

    line[line_size-1]=ZERO;
    len=strlen(line);  len--;
    if(line[len] == RTN)  line[len]=ZERO;

    quote=0;
    i=0;
    while(line[i])
    {
        if(line[i] == '"')  quote=!quote;
        if(!quote)
        {
            if(line[i] == TAB)
                line[i]=SPACE;
            else if(line[i] == ';' || line[i] == '#')
            {   line[i]=ZERO; break;   }
        }
        i++;
    }
    trim_head_space(line);
    trim_tail_space(line);
}/*}}}*/

static int _cnfg(char *argv0)
{/*{{{*/
    char buf[LONG_FILE_NM_SIZE+1];
    FILE *fp;
    char users[LONG_FILE_NM_SIZE+1];
    char section[LONG_FILE_NM_SIZE+1];
    int wsclient_max_num;
#ifndef _MY_DEBUG
    char *svcenv_dir;
#endif
    char *svcenv_cnfg;
    CNFG cnfg;
    struct cnfg_property property;
    struct cnfg_property *array;
    int array_num;
    char *p;
    int res;
    int i;

    // tuxedo lic.txt
    if((p=getenv("TUXDIR")) == NULL)
    {
        fprintf(stderr, "%s: TUXDIR not set\n", __func__);
        return(-1);
    }
    sprintf(buf, "%s/udataobj/lic.txt", p);
    if((fp=fopen(buf, "r")) == NULL)
    {
        fprintf(stderr, "TUXDIR/udataobj/lic.txt read fail\n");
        return(-1);
    }
    CLR_BUF(users);
    while(fgets(buf, sizeof(buf), fp))
    {
        _trim_line(buf, sizeof(buf));
        if(BUF_IS_CLR(buf))  continue;
//        printf("%s\n", buf);
        if(sscanf(buf, "[%[^]]", section) == 1)
        {
            if(strstr(section, "BEA TUXEDO") == NULL)
                break;
        }
        if(strncmp(buf, "USERS=", strlen("USERS=")) == 0)
        {
            strcpy(users, buf+strlen("USERS="));
            trim_space(users);
            break;
        }
    }
    fclose(fp);

    if(!BUF_IS_CLR(users))
    {
        if(strcasecmp(users, "unlimited") == 0)
        {   wsclient_max_num=WSCLIENT_MAX_NUM;   }
        else
        {
            if((wsclient_max_num=atoi(users)) > 0)
            {
                if(wsclient_max_num > WSCLIENT_MAX_NUM)
                    wsclient_max_num=WSCLIENT_MAX_NUM;
            }
            else
            {   wsclient_max_num=WSCLIENT_DEF_NUM;   }
        }
    }
    else
    {   wsclient_max_num=WSCLIENT_DEF_NUM;   }

    printf("\n");
    printf("======= tuxagent wsclients =======\n");
    printf("  License support:   %s\n", users);
    printf("  Application limit: %d\n", wsclient_max_num);

    /*----- cnfg -----*/
#ifndef _MY_DEBUG
    svcenv_dir=getenv("SVCENV_DIR");
    if(!svcenv_dir)
    {
        fprintf(stderr, "agent: SVCENV_DIR not set\n");
        return(-1);
    }
#endif
    svcenv_cnfg=getenv("SVCENV_CNFG");
    if(!svcenv_cnfg)
    {
        fprintf(stderr, "agent: SVCENV_CNFG not set\n");
        return(-1);
    }
    res=cnfg_load(svcenv_cnfg, &cnfg);
    if(res)
    {
        if(res > 0)
            fprintf(stderr, "agent: svcenv.cnfg line %d error\n",
                    res);
        else
            fprintf(stderr, "agent: load svcenv.cnfg fail, errcode:%d\n",
                    res);
        return(-1);
    }

    // ERRLOG
#ifdef _MY_DEBUG
    CLR_BUF(cnfg_info.errlog_location);
    init_errlog(argv0, NULL);
#else
    sprintf(cnfg_info.errlog_location, "%s/log", svcenv_dir);
    res=cnfg_get_property(cnfg, "ERRLOG", "LOCATION", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr,
                    "agent: get ERRLOG.LOCATION fail, errcode:%d\n",
                    res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
        {
            if(property.value[0] == '/')
                strcpy(cnfg_info.errlog_location, property.value);
            else
                sprintf(cnfg_info.errlog_location, "%s/%s",
                        svcenv_dir, property.value);
        }
    }
    res=init_errlog(argv0, cnfg_info.errlog_location);
    if(res)
    {
        fprintf(stderr, "agent: init_errlog fail, errcode:%d\n", res);
        return(-1);
    }
#endif

    // IPCKEY
    res=cnfg_get_property(cnfg, "GLOBAL", "IPCKEY", 0, &property);
    if(res)
    {
        fprintf(stderr,
                "agent: get IPCKEY in svcenv.cnfg fail, errcode:%d\n",
                res);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || !str_is_dec(property.value))
    {
        fprintf(stderr, "agent: IPCKEY invalid in svcenv.cnfg\n");
        return(-1);
    }
    cnfg_info.ipckey=atoi(property.value);

    /*--- AGENT ---*/
    // SERVER_PORT
    res=cnfg_get_property(cnfg, "AGENT", "SERVER_PORT", 0, &property);
    if(res)
    {
        fprintf(stderr,
                "agent: get AGENT.SERVER_PORT fail, errcode:%d\n",
                res);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || (res=atoi(property.value)) < 1024)
    {
        fprintf(stderr,
                "agent: AGENT.SERVER_PORT invalid in svcenv.cnfg\n");
        return(-1);
    }
    cnfg_info.server_port=res;
    // THREADS
    res=cnfg_get_property(cnfg, "AGENT", "THREADS", 0, &property);
    if(res)
    {
        fprintf(stderr,
                "agent: get AGENT.THREADS fail, errcode:%d\n",
                res);
        return(-1);
    }
    if(BUF_IS_CLR(property.value))
    {
        fprintf(stderr,
                "agent: AGENT.THREADS invalid in svcenv.cnfg\n");
        return(-1);
    }
    cnfg_info.threads=atoi(property.value);
    if(cnfg_info.threads == 0 || cnfg_info.threads > wsclient_max_num)
        cnfg_info.threads=WSCLIENT_DEF_NUM;
    else
        cnfg_info.threads=WSCLIENT_DEF_NUM;
  //printf("  Application limit: %d\n", wsclient_max_num);
    printf("  svcenv.sh set:     %s\n", property.value);
    printf("  Actually:          %d\n", cnfg_info.threads);
    printf("==================================\n");

    /*--- SVCNODE ---*/
    array_num=cnfg_property_array(cnfg, "SVCNODE", 0, &array);
    if(array_num < 0)
    {
        fprintf(stderr,
                "agent: get SVCNODE array fail, errcode:%d\n",
                res);
        return(-1);
    }
    if(array_num > 0)
    {/*{{{*/
        ALLOC_ARRAY_DOERR(cnfg_info._svcnode_.svcnode,
                struct _cnfg_svcnode, array_num,
                cnfg_info._svcnode_.num,
                fprintf(stderr,
                    "agent: alloc cnfg_info._svcnode_.svcnode fail\n");
                return(-1));
        for(i=0; i<array_num; ++i)
        {
            struct _cnfg_svcnode *cnfg_sn=
                &cnfg_info._svcnode_.svcnode[i];
            if(array[i].type != CNFG_PROPERTY_COMPOSITE)
            {
                fprintf(stderr, "agent: svcnode(%d) invalid\n", i);
                return(-1);
            }
            strcpy(cnfg_sn->name, array[i].name);
            res=cnfg_get_subproperty(cnfg, "SVCNODE",
                    array[i].name, "ADDR", 0, &property);
            if(res || BUF_IS_CLR(property.value) ||
                    strlen(property.value) > LONG_FILE_NM_SIZE)
            {
                fprintf(stderr, "agent: SVCNODE.%s.ADDR invalid\n",
                        array[i].name);
                return(-1);
            }
            strcpy(cnfg_sn->addr, property.value);
            res=cnfg_get_subproperty(cnfg, "SVCNODE", array[i].name,
                    "MODE", 0, &property);
            if(res)
            {
                if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND) 
                {
                    fprintf(stderr,
                            "agent: get SVCNODE.%s.MODE fail, "
                            "errcode:%d\n",
                            array[i].name, res);
                    return(-1);
                }
                cnfg_sn->mode=SN_MODE_PERMANENT;
            }
            else
            {
                if(!BUF_IS_CLR(property.value) &&
                        strcasecmp(property.value, "ONESHOT") == 0)
                    cnfg_sn->mode=SN_MODE_ONESHOT;
                else
                    cnfg_sn->mode=SN_MODE_PERMANENT;
            }
        }
        free(array);
    }/*}}}*/

    return(0);
}/*}}}*/

static int _start()
{/*{{{*/
    SOCKET *sock_pair;

    sig_ignore(SIGPIPE);
    ep_init();

    if(worker_start(&sock_pair))
    {
        fprintf(stderr, "agent: worker start fail\n");
        return(-1);
    }
    if(listener_start(sock_pair))
    {
        fprintf(stderr, "agent: listener start fail\n");
        return(-1);
    }
    free(sock_pair);

    return(monitor_start());
}/*}}}*/

int main(int argc, char *argv[])
{
#ifndef _MY_DEBUG
    daemon(1, 1);
#endif
    if(_cnfg(argv[0]))
        return(-1);
    return(_start());
}
